/*     */ package com.zimbra.cs.servlet.util;
/*     */ 
/*     */ import com.google.common.base.Joiner;
/*     */ import com.zimbra.common.account.Key.AccountBy;
/*     */ import com.zimbra.common.service.ServiceException;
/*     */ import com.zimbra.common.util.BlobMetaData;
/*     */ import com.zimbra.common.util.BlobMetaDataEncodingException;
/*     */ import com.zimbra.common.util.HttpUtil;
/*     */ import com.zimbra.common.util.Log;
/*     */ import com.zimbra.common.util.Pair;
/*     */ import com.zimbra.common.util.StringUtil;
/*     */ import com.zimbra.common.util.ZimbraLog;
/*     */ import com.zimbra.cs.account.Account;
/*     */ import com.zimbra.cs.account.AuthToken;
/*     */ import com.zimbra.cs.account.AuthTokenException;
/*     */ import com.zimbra.cs.account.CsrfTokenKey;
/*     */ import com.zimbra.cs.account.Provisioning;
/*     */ import com.zimbra.cs.account.ZimbraAuthToken;
/*     */ import com.zimbra.cs.service.AuthProvider;
/*     */ import java.io.PrintStream;
/*     */ import java.net.MalformedURLException;
/*     */ import java.net.URL;
/*     */ import java.util.ArrayList;
/*     */ import java.util.Arrays;
/*     */ import java.util.HashMap;
/*     */ import java.util.List;
/*     */ import java.util.Map;
/*     */ import javax.servlet.http.HttpServletRequest;
/*     */ import javax.servlet.http.HttpServletResponse;
/*     */ import org.apache.commons.codec.DecoderException;
/*     */ import org.apache.commons.codec.binary.Hex;
/*     */ import org.apache.commons.fileupload.FileItem;
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ public final class CsrfUtil
/*     */ {
/*     */   protected static final String C_ID = "id";
/*     */   protected static final String C_EXP = "exp";
/*     */   protected static final String C_SALT_ID = "sid";
/*     */   protected static final String PARAM_CSRF_TOKEN = "csrfToken";
/*     */   
/*     */   public static boolean isCsrfRequestBasedOnReferrer(HttpServletRequest req, String[] allowedRefHost)
/*     */     throws MalformedURLException
/*     */   {
/*  84 */     List<String> allowedRefHostList = Arrays.asList(allowedRefHost);
/*  85 */     boolean csrfReq = false;
/*     */     
/*  87 */     String method = req.getMethod();
/*  88 */     if (!method.equalsIgnoreCase("POST")) {
/*  89 */       csrfReq = false;
/*  90 */       return csrfReq;
/*     */     }
/*     */     
/*  93 */     String host = getRequestHost(req);
/*  94 */     String referrer = req.getHeader("Referer");
/*  95 */     String refHost = null;
/*     */     
/*     */ 
/*  98 */     if (!StringUtil.isNullOrEmpty(referrer)) {
/*  99 */       URL refURL = null;
/* 100 */       if ((referrer.contains("http")) || (referrer.contains("https"))) {
/* 101 */         refURL = new URL(referrer);
/*     */       } else {
/* 103 */         refURL = new URL("http://" + referrer);
/*     */       }
/* 105 */       refHost = refURL.getHost().toLowerCase();
/*     */     }
/*     */     
/* 108 */     if (refHost == null) {
/* 109 */       csrfReq = false;
/* 110 */     } else if (refHost.equalsIgnoreCase(host)) {
/* 111 */       csrfReq = false;
/*     */     }
/* 113 */     else if ((allowedRefHost != null) && (allowedRefHostList.contains(refHost))) {
/* 114 */       csrfReq = false;
/*     */     } else {
/* 116 */       csrfReq = true;
/*     */     }
/*     */     
/*     */ 
/* 120 */     if (ZimbraLog.soap.isDebugEnabled()) {
/* 121 */       ZimbraLog.soap.debug("Host : %s, Referrer host :%s, Allowed Hosts:[%s] Soap req is %s", new Object[] { host, refHost, Joiner.on(',').join(allowedRefHostList), csrfReq ? " not allowed." : " allowed." });
/*     */     }
/*     */     
/*     */ 
/* 125 */     return csrfReq;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public static String getRequestHost(HttpServletRequest req)
/*     */   {
/* 135 */     String host = HttpUtil.getVirtualHost(req);
/* 136 */     if (host == null) {
/* 137 */       return host;
/*     */     }
/* 139 */     String temp = host;
/*     */     
/* 141 */     if (temp.indexOf(":") != -1) {
/* 142 */       int endIndex = temp.indexOf(":");
/* 143 */       temp = host.substring(0, endIndex);
/*     */     }
/* 145 */     if (ZimbraLog.soap.isTraceEnabled()) {
/* 146 */       ZimbraLog.soap.trace("Original host : " + host + " returning: " + temp);
/*     */     }
/*     */     
/* 149 */     temp = temp.toLowerCase();
/* 150 */     return temp;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public static AuthToken getAuthTokenFromReq(HttpServletRequest req)
/*     */   {
/* 160 */     AuthToken at = null;
/*     */     try {
/* 162 */       boolean isAdminRequest = AuthUtil.isAdminRequest(req);
/* 163 */       at = AuthProvider.getAuthToken(req, isAdminRequest);
/*     */     } catch (ServiceException|AuthTokenException e) {
/* 165 */       ZimbraLog.security.info("Error extracting auth token from the request. " + e.getMessage());
/*     */     }
/*     */     
/* 168 */     return at;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public static boolean doCsrfCheck(HttpServletRequest req, AuthToken authToken)
/*     */     throws MalformedURLException
/*     */   {
/* 183 */     boolean csrfReq = true;
/* 184 */     csrfReq = isPostReq(req);
/* 185 */     if (csrfReq) {
/* 186 */       if (authToken != null) {
/* 187 */         if (!authToken.isCsrfTokenEnabled()) {
/* 188 */           csrfReq = isCsrfTokenCreated(authToken);
/*     */         }
/*     */       } else {
/* 191 */         csrfReq = false;
/*     */       }
/*     */     }
/* 194 */     if (ZimbraLog.misc.isDebugEnabled()) {
/* 195 */       String reqUrl = req.getRequestURI();
/* 196 */       ZimbraLog.misc.debug("ReqURL : " + reqUrl + (csrfReq ? " needs to " : " does not need to ") + "pass through CSRF check");
/*     */     }
/*     */     
/*     */ 
/* 200 */     return csrfReq;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */   public static boolean isPostReq(HttpServletRequest req)
/*     */   {
/* 207 */     boolean postReq = true;
/* 208 */     String method = req.getMethod();
/* 209 */     if ((!method.equalsIgnoreCase("POST")) && (!method.equalsIgnoreCase("PUT")) && (!method.equalsIgnoreCase("DELETE")))
/*     */     {
/* 211 */       postReq = false;
/*     */     }
/* 213 */     return postReq;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public static boolean isCsrfTokenCreated(AuthToken authToken)
/*     */   {
/* 222 */     boolean csrfTokenCreated = false;
/* 223 */     ZimbraLog.misc.debug("isCsrfTokenCreated()");
/*     */     try {
/* 225 */       Account account = getAccount(authToken, Boolean.TRUE.booleanValue());
/* 226 */       if (account != null) {
/* 227 */         crumb = authToken.getCrumb();
/* 228 */         String[] validCsrfTokens = account.getMultiAttr("zimbraCsrfTokenData");
/* 229 */         List<String> validCsrfTokenList = Arrays.asList(validCsrfTokens);
/* 230 */         for (String csrfTokenData : validCsrfTokenList) {
/* 231 */           String[] data = csrfTokenData.split(":");
/* 232 */           if (data[1].equals(crumb)) {
/* 233 */             csrfTokenCreated = true;
/* 234 */             break;
/*     */           }
/*     */         }
/*     */       }
/*     */     } catch (ServiceException|AuthTokenException e) { String crumb;
/* 239 */       ZimbraLog.misc.info("Error fetching list of CSRF tokens" + e.getMessage());
/*     */     }
/* 241 */     return csrfTokenCreated;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */   public static Account getAccount(AuthToken authToken, boolean loadFromLdap)
/*     */     throws ServiceException
/*     */   {
/* 250 */     Account account = null;
/*     */     
/* 252 */     if (loadFromLdap) {
/* 253 */       Provisioning prov = Provisioning.getInstance();
/* 254 */       account = prov.get(Key.AccountBy.id, authToken.getAccountId(), Boolean.TRUE.booleanValue());
/* 255 */       if (account != null) {
/* 256 */         prov.reload(account);
/*     */       }
/*     */     } else {
/* 259 */       account = authToken.getAccount();
/*     */     }
/* 261 */     return account;
/*     */   }
/*     */   
/*     */   public static boolean isValidCsrfToken(String csrfToken, AuthToken authToken) {
/* 265 */     if (StringUtil.isNullOrEmpty(csrfToken)) {
/* 266 */       return false;
/*     */     }
/*     */     
/* 269 */     String hmacFromToken = null;
/* 270 */     String crumb = null;
/* 271 */     String keyVersion = null;
/* 272 */     boolean validToken = false;
/* 273 */     boolean loadFromLdap = false;
/*     */     try
/*     */     {
/* 276 */       Pair<String, String> data = parseCsrfToken(csrfToken);
/* 277 */       hmacFromToken = (String)data.getFirst();
/* 278 */       keyVersion = (String)data.getSecond();
/* 279 */       crumb = authToken.getCrumb();
/* 280 */       Account account = getAccount(authToken, loadFromLdap);
/* 281 */       if (account == null) {
/* 282 */         return false;
/*     */       }
/* 284 */       validToken = validateCsrfToken(hmacFromToken, crumb, keyVersion, validToken, account);
/* 285 */       if (!validToken)
/*     */       {
/*     */ 
/* 288 */         ZimbraLog.misc.info("CSRF token was invalid, rechecking with account object from LDAP.");
/* 289 */         loadFromLdap = true;
/* 290 */         account = getAccount(authToken, loadFromLdap);
/* 291 */         validToken = validateCsrfToken(hmacFromToken, crumb, keyVersion, validToken, account);
/* 292 */         if (ZimbraLog.misc.isDebugEnabled()) {
/* 293 */           ZimbraLog.misc.debug("The csrfToken second check: " + (validToken ? "is valid." : " is invalid."));
/*     */         }
/*     */       }
/*     */     } catch (AuthTokenException|ServiceException e) {
/* 297 */       ZimbraLog.misc.info("Error decoding CSRF token, " + e.getMessage());
/*     */       
/* 299 */       validToken = false;
/*     */     }
/*     */     
/* 302 */     if (ZimbraLog.misc.isDebugEnabled()) {
/* 303 */       ZimbraLog.misc.debug("The csrfToken: " + (validToken ? "is valid." : " is invalid."));
/*     */     }
/* 305 */     return validToken;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   private static boolean validateCsrfToken(String hmacFromToken, String crumb, String keyVersion, boolean validToken, Account account)
/*     */     throws ServiceException, AuthTokenException
/*     */   {
/* 321 */     String csrfTokenData = getTokenDataFromLdap(crumb, account);
/* 322 */     if (csrfTokenData != null) {
/* 323 */       CsrfTokenKey key = CsrfTokenKey.getVersion(keyVersion);
/* 324 */       if (key == null) {
/* 325 */         throw new AuthTokenException("unknown key version");
/*     */       }
/* 327 */       String computedHmac = ZimbraAuthToken.getHmac(csrfTokenData, key.getKey());
/*     */       
/* 329 */       if (computedHmac.equals(hmacFromToken)) {
/* 330 */         Map<?, ?> decodedData = getAttrs(csrfTokenData);
/* 331 */         long expirationTime = Long.parseLong((String)decodedData.get("exp"));
/* 332 */         long currentTime = System.currentTimeMillis();
/* 333 */         if (currentTime < expirationTime) {
/* 334 */           validToken = true;
/*     */         }
/*     */       }
/*     */     }
/* 338 */     return validToken;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public static Pair<String, String> parseCsrfToken(String csrfToken)
/*     */     throws AuthTokenException
/*     */   {
/* 350 */     int pos = csrfToken.indexOf('_');
/* 351 */     if (pos == -1) {
/* 352 */       throw new AuthTokenException("invalid authtoken format");
/*     */     }
/* 354 */     String ver = csrfToken.substring(0, pos);
/*     */     
/* 356 */     String hmac = csrfToken.substring(pos + 1);
/* 357 */     return new Pair(hmac, ver);
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   private static String getTokenDataFromLdap(String crumb, Account account)
/*     */     throws ServiceException
/*     */   {
/* 367 */     String csrfTokenData = null;
/* 368 */     String[] validCsrfTokens = account.getMultiAttr("zimbraCsrfTokenData");
/*     */     
/* 370 */     List<String> validCsrfTokenList = Arrays.asList(validCsrfTokens);
/* 371 */     if (ZimbraLog.misc.isDebugEnabled()) {
/* 372 */       ZimbraLog.misc.debug("Existing CSRF token data: " + validCsrfTokenList);
/*     */     }
/* 374 */     validCsrfTokenList = purgeOldCsrfTokens(validCsrfTokenList, account);
/* 375 */     for (String validCsrfToken : validCsrfTokenList) {
/* 376 */       String[] temp = validCsrfToken.split(":");
/* 377 */       if (temp[1].equals(crumb)) {
/* 378 */         csrfTokenData = temp[0];
/* 379 */         break;
/*     */       }
/*     */     }
/*     */     
/* 383 */     return csrfTokenData;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   private static Map<?, ?> getAttrs(String data)
/*     */     throws AuthTokenException
/*     */   {
/*     */     try
/*     */     {
/* 396 */       String decoded = new String(Hex.decodeHex(data.toCharArray()));
/* 397 */       return BlobMetaData.decode(decoded);
/*     */     } catch (DecoderException e) {
/* 399 */       throw new AuthTokenException("decoding exception", e);
/*     */     } catch (BlobMetaDataEncodingException e) {
/* 401 */       throw new AuthTokenException("blob decoding exception", e);
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   private static List<String> purgeOldCsrfTokens(List<String> validCsrfTokenSaltList, Account account)
/*     */     throws ServiceException
/*     */   {
/* 413 */     List<String> validList = new ArrayList();
/* 414 */     long now = System.currentTimeMillis();
/* 415 */     HashMap<String, Object> toPurge = new HashMap();
/* 416 */     for (String csrfTokenSalt : validCsrfTokenSaltList) {
/* 417 */       String[] temp = csrfTokenSalt.split(":");
/* 418 */       long tokenExpiration = Long.parseLong(temp[2]);
/* 419 */       if (now < tokenExpiration) {
/* 420 */         validList.add(csrfTokenSalt);
/*     */       } else {
/* 422 */         StringUtil.addToMultiMap(toPurge, "-zimbraCsrfTokenData", csrfTokenSalt);
/*     */       }
/*     */     }
/* 425 */     if (toPurge.size() > 0) {
/* 426 */       account.modify(toPurge);
/*     */     }
/* 428 */     return validList;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public static String generateCsrfToken(String accountId, long authTokenExpiration, int tokenSalt, AuthToken at)
/*     */     throws ServiceException
/*     */   {
/*     */     try
/*     */     {
/* 445 */       String crumb = at.getCrumb();
/* 446 */       String tokenData = getExistingCsrfTokenForThisAuthToken(at, crumb);
/* 447 */       if (tokenData == null)
/*     */       {
/* 449 */         StringBuilder encodedBuff = new StringBuilder(64);
/* 450 */         BlobMetaData.encodeMetaData("id", accountId, encodedBuff);
/* 451 */         BlobMetaData.encodeMetaData("exp", Long.toString(authTokenExpiration), encodedBuff);
/* 452 */         BlobMetaData.encodeMetaData("sid", tokenSalt, encodedBuff);
/* 453 */         tokenData = new String(Hex.encodeHex(encodedBuff.toString().getBytes()));
/*     */       }
/* 455 */       CsrfTokenKey key = getCurrentKey();
/* 456 */       String hmac = ZimbraAuthToken.getHmac(tokenData, key.getKey());
/* 457 */       String encoded = key.getVersion() + "_" + hmac;
/* 458 */       storeTokenData(tokenData, at, authTokenExpiration, crumb);
/* 459 */       return encoded;
/*     */     } catch (AuthTokenException e) {
/* 461 */       throw ServiceException.FAILURE("Error generating Auth Token, " + e.getMessage(), e);
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   private static String getExistingCsrfTokenForThisAuthToken(AuthToken authToken, String crumb)
/*     */     throws ServiceException
/*     */   {
/* 474 */     Account account = getAccount(authToken, Boolean.TRUE.booleanValue());
/* 475 */     if (account != null) {
/* 476 */       return getTokenDataFromLdap(crumb, account);
/*     */     }
/* 478 */     return null;
/*     */   }
/*     */   
/*     */   protected static CsrfTokenKey getCurrentKey() throws AuthTokenException
/*     */   {
/*     */     try {
/* 484 */       return CsrfTokenKey.getCurrentKey();
/*     */     }
/*     */     catch (ServiceException e) {
/* 487 */       ZimbraLog.misc.debug("Unable to get latest CsrfTokenKey", e);
/* 488 */       throw new AuthTokenException("unable to get CsrfTokenKey", e);
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   private static void storeTokenData(String data, AuthToken authToken, long authTokenExpiration, String crumb)
/*     */     throws ServiceException
/*     */   {
/* 502 */     Account account = getAccount(authToken, Boolean.TRUE.booleanValue());
/* 503 */     if (account != null) {
/* 504 */       String[] validCsrfTokens = account.getMultiAttr("zimbraCsrfTokenData");
/*     */       
/* 506 */       String newToken = data + ":" + crumb + ":" + authTokenExpiration;
/* 507 */       HashMap<String, Object> mods = new HashMap();
/* 508 */       boolean needToAdd = true;
/* 509 */       for (String tokenData : validCsrfTokens) {
/* 510 */         String[] temp = tokenData.split(":");
/* 511 */         String tokenCrumb = temp[1];
/* 512 */         if (tokenCrumb.equals(crumb)) {
/* 513 */           if (!tokenData.equals(newToken)) {
/* 514 */             StringUtil.addToMultiMap(mods, "-zimbraCsrfTokenData", tokenData);
/*     */           } else {
/* 516 */             ZimbraLog.misc.debug("token already stored in LDAP");
/* 517 */             needToAdd = false;
/*     */           }
/*     */         }
/*     */       }
/* 521 */       if (needToAdd) {
/* 522 */         StringUtil.addToMultiMap(mods, "+zimbraCsrfTokenData", newToken);
/*     */       }
/* 524 */       if (mods.size() > 0) {
/* 525 */         account.modify(mods);
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */   public static CsrfTokenKey getCsrfTokenKey() throws ServiceException {
/* 531 */     return CsrfTokenKey.getCurrentKey();
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */   public static AuthToken getAuthTokenFromResponse(HttpServletResponse resp)
/*     */     throws AuthTokenException
/*     */   {
/* 540 */     List<String> headers = (List)resp.getHeaders("Set-Cookie");
/* 541 */     AuthToken at = null;
/* 542 */     for (String s : headers) {
/* 543 */       if ((!StringUtil.isNullOrEmpty(s)) && (s.contains("ZM_AUTH_TOKEN"))) {
/* 544 */         String[] temp = s.split("=");
/* 545 */         int index = temp[1].indexOf(";");
/* 546 */         String token = temp[1].substring(0, index);
/* 547 */         at = AuthToken.getAuthToken(token);
/*     */       }
/*     */     }
/* 550 */     return at;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */   public static String generateCsrfTokenTest(String accountId, long authTokenExpiration, int tokenSalt, String sessionId)
/*     */     throws AuthTokenException
/*     */   {
/* 558 */     StringBuilder encodedBuff = new StringBuilder(64);
/* 559 */     BlobMetaData.encodeMetaData("id", accountId, encodedBuff);
/* 560 */     BlobMetaData.encodeMetaData("exp", Long.toString(authTokenExpiration), encodedBuff);
/* 561 */     BlobMetaData.encodeMetaData("sid", tokenSalt, encodedBuff);
/*     */     
/*     */ 
/* 564 */     String data = new String(Hex.encodeHex(encodedBuff.toString().getBytes()));
/* 565 */     CsrfTokenKey key = getCurrentKey();
/* 566 */     String hmac = ZimbraAuthToken.getHmac(data, key.getKey());
/* 567 */     String encoded = key.getVersion() + "_" + hmac + "_" + data;
/* 568 */     return encoded;
/*     */   }
/*     */   
/*     */   public static boolean checkCsrfInMultipartFileUpload(List<FileItem> items, AuthToken at)
/*     */   {
/* 573 */     for (FileItem item : items) {
/* 574 */       if ((item.isFormField()) && 
/* 575 */         (item.getFieldName().equals("csrfToken"))) {
/* 576 */         if (item.getSize() >= 128L) break;
/* 577 */         String csrfToken = item.getString();
/* 578 */         if (isValidCsrfToken(csrfToken, at)) {
/* 579 */           return true;
/*     */         }
/* 581 */         ZimbraLog.misc.debug("Csrf token : %s recd in file upload is invalid.", new Object[] { csrfToken });
/*     */         
/* 583 */         break;
/*     */       }
/*     */     }
/*     */     
/*     */ 
/* 588 */     return false;
/*     */   }
/*     */   
/*     */   public static void main(String[] args)
/*     */   {
/*     */     try {
/* 594 */       AuthToken at = ZimbraAuthToken.getAuthToken("0_f66f9e23c3d6ec89c0723375489c729b13b108d9_69643d33363a34313537336365352d303035352d343066362d626235372d6264396238663136663666393b6578703d31333a313430333935303235363538323b747970653d363a7a696d6272613b7469643d31303a313837363638363831333b76657273696f6e3d303a3b637372663d313a313b");
/* 595 */       String csrfToken = "0_a00d6f6af20bf183ab63911ab648a7869793158e";
/* 596 */       boolean result = isValidCsrfToken(csrfToken, at);
/* 597 */       System.out.println(result);
/*     */     } catch (Exception e) {
/* 599 */       e.printStackTrace();
/*     */     }
/*     */   }
/*     */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/servlet/util/CsrfUtil.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */